package com.appspot.codelab.docs.client.repository;

import com.appspot.codelab.docs.client.impl.Map;
import com.appspot.codelab.docs.client.repository.RepositoryDirectory.RepositoryFile;
import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.rpc.AsyncCallback;

public class RepositoryServiceClient {
	
  private final RepositoryServiceAsync service = GWT.create(RepositoryService.class);

  public void projectExists(String project, AsyncCallback<Boolean> callback) {
	service.projectExists(project, callback);
  }
  
  public void createSourceDirectory(String project, String path,
	    String username, String password, AsyncCallback<Boolean> callback) {
	service.createSourceDirectory(project, path, username, password, callback);
  }
  
  public void getUser(AsyncCallback<RepositoryUser> callback) {
	service.getUser(callback);
  }
  
  public void getProject(String projectName, AsyncCallback<RepositoryProject> callback) {
	service.getProject(projectName, callback);
  }
  
  public void putProject(String projectName, String projectToken,
	    AsyncCallback<RepositoryProject> callback) {
	service.putProject(projectName, projectToken, callback);
  }
  
  public void logout(AsyncCallback<String> callback) {
	service.logout(callback);
  }
  
  public void getSourceDirectory(String project, String path, String revision,
	    final AsyncCallback<RepositoryDirectory> callback) {
    service.getSourceDirectory(project, path, revision, new AsyncCallback<String>() {
		@Override
		public void onFailure(Throwable caught) {
		  callback.onFailure(caught);
		}
		@Override
		public void onSuccess(String result) {
		  if (result == null) {
			callback.onFailure(new Exception("Invalid path."));
		  } else {
		    RepositoryDirectory dir = evalDirectory(result);
		    callback.onSuccess(dir);
		  }
		}
    });
  }

  public void getNewSourceFile(RepositoryUser user, AsyncCallback<RepositoryFile> callback) {
	callback.onSuccess(RepositoryFile.newInstance(user.getEmail()));
  }
  
  public void getSourceFile(String project, String path, String revision,
	    final AsyncCallback<RepositoryFile> callback) {
	int c = path.lastIndexOf('/');
	if (c >= 0) {
	  String dir = path.substring(0, c);
	  final String fileName = path.substring(c + 1);
	  getSourceDirectory(project, dir, revision,
	      new AsyncCallback<RepositoryDirectory>() {
			@Override
			public void onFailure(Throwable caught) {
			  callback.onFailure(caught);
			}
			@Override
			public void onSuccess(RepositoryDirectory result) {
			  if (result != null) {
				Map<RepositoryFile> files = result.getFilePage().getFiles();
				for (String path : files.keys()) {
				  if (path.equals(fileName)) {
					callback.onSuccess(files.get(path));
				    return;
				  }
				}
			  }
			  callback.onFailure(new Exception("Invalid file path."));
			}
	  });
	} else {
	  callback.onFailure(new Exception("Invalid file path."));
	}
  }

  public void getSourceFileContents(String project, String path, String revision,
	    AsyncCallback<String> callback) {
	service.getSourceFileContents(project, path, revision, callback);
  }

  public void uploadSourceFile(final String project, final String path,
		final String username, final String password,
		String contents, final AsyncCallback<RepositoryFile> callback) {
    service.uploadSourceFile(project, path, username, password, contents,
        new AsyncCallback<Boolean>() {
			@Override
			public void onFailure(Throwable caught) {
			  callback.onFailure(caught);
			}
			@Override
			public void onSuccess(Boolean result) {
			  if (result) {
				getSourceFile(project, path, null, callback);
			  } else {
				callback.onFailure(new Exception("File upload failed."));
			  }
			}
    });
  }

  public void uploadProjectFile(String project, String path, String username, String password,
		String contents, String summary, String[] labels, AsyncCallback<Boolean> callback) {
    service.uploadProjectFile(project, path, username, password, contents, summary, labels, callback);
  }
  
  public void deleteSourceFile(String project, String path,
		String username, String password,
	    final AsyncCallback<Boolean> callback) {
	  service.deleteSourceFile(project, path, username, password, callback);
  }
  
  public void renameSourceFile(final String project, final String path,
		final String newPath, final String username, final String password,
	    final AsyncCallback<RepositoryFile> callback) {
	service.renameSourceFile(project, path, newPath, username, password, 
	        new AsyncCallback<Boolean>() {
		@Override
		public void onFailure(Throwable caught) {
		  callback.onFailure(caught);
		}
		@Override
		public void onSuccess(Boolean result) {
		  if (result) {
			getSourceFile(project, newPath, null, callback);
		  } else {
			callback.onFailure(new Exception("File rename failed."));
		  }
		}
    });
  }
  
  private native RepositoryDirectory evalDirectory(String json) /*-{
  	var dirs = eval('(' + json + ')');
  	for (var dir in dirs) {
  	  dirs[dir].name = dir;
  	  return dirs[dir];
  	}
    return null;
  }-*/;

}
